博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
ASP.Net 重写IHttpModule 来拦截 HttpApplication 实现HTML资源压缩和空白过滤
阅读量:4654 次
发布时间:2019-06-09

本文共 17414 字,大约阅读时间需要 58 分钟。

务实直接上代码:

1. 重写FilterModule.cs

1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 using System.Web; 7 using System.Text.RegularExpressions; 8 using System.IO.Compression; 9 10 namespace Compress.FilterModule11 {12     public class FilterModule : IHttpModule13     {14         public void Dispose()15         {16             //17         }18 19         /// 20         /// Init method is only used to register the desired event21         /// 22         /// 23         public void Init(HttpApplication context)24         {25             context.BeginRequest += new EventHandler(context_BeginRequest);26             //context.EndRequest += new EventHandler(context_EndRequest);27             //context.PostRequestHandlerExecute += new EventHandler(context_PostRequestHandlerExecute);28         }29 30 31         /// 32         /// Handles the BeginRequest event of the context control.33         /// 34         /// The source of the event.35         /// The 
instance containing the event data.36 void context_BeginRequest(object sender, EventArgs e)37 {38 HttpApplication app = sender as HttpApplication;39 HttpContext context = app.Context;40 if (context.CurrentHandler is System.Web.UI.Page)41 {42 bool isPage = context.CurrentHandler.IsReusable;43 }44 if (app.Request.RawUrl.Contains(".aspx") || app.Request.RawUrl.EndsWith("/"))45 {46 // HttpContext context = app.Context;47 HttpRequest request = context.Request;48 string acceptEncoding = request.Headers["Accept-Encoding"];49 HttpResponse response = context.Response;50 if (!string.IsNullOrEmpty(acceptEncoding))51 {52 acceptEncoding = acceptEncoding.ToUpperInvariant();53 if (acceptEncoding.Contains("GZIP"))54 {55 //var straem = new GZipStream(response.Filter, CompressionMode.Compress);56 response.Filter = new CompressWhitespaceFilter(response.Filter, CompressOptions.GZip);57 response.AppendHeader("Content-encoding", "gzip");58 }59 else if (acceptEncoding.Contains("DEFLATE"))60 {61 response.Filter = new CompressWhitespaceFilter(context.Response.Filter, CompressOptions.Deflate);62 response.AppendHeader("Content-encoding", "deflate");63 }64 }65 response.Cache.VaryByHeaders["Accept-Encoding"] = true;66 }67 }68 69 // Test70 //void context_BeginRequest(object sender, EventArgs e)71 //{72 // HttpApplication application = (HttpApplication)sender;73 // HttpContext context = application.Context;74 // context.Response.ContentType = "text/html";75 // context.Response.Charset = "GB2312";76 // context.Response.ContentEncoding = Encoding.Default;77 // context.Response.Write("

Treatment from HttpModule,Begin...


");78 //}79 80 // Test81 //void context_EndRequest(object sender, EventArgs e)82 //{83 // HttpApplication application = (HttpApplication)sender;84 // HttpContext context = application.Context;85 // context.Response.ContentType = "text/html";86 // context.Response.Charset = "GB2312";87 // context.Response.ContentEncoding = Encoding.Default;88 // context.Response.Write("

Treatment from HttpModule,End...

");89 //}90 91 }92 }

 

2. 处理压缩和匹配自定义过滤 CompressWhitespaceFilter.cs

1 using System;  2 using System.Collections.Generic;  3 using System.Linq;  4 using System.Web;  5 using System.IO;  6 using System.Text;  7 using System.Text.RegularExpressions;  8 using System.IO.Compression;  9  10 namespace Compress.ModuleDemo 11 { 12     public enum CompressOptions 13     { 14         GZip, 15         Deflate, 16         None 17     } 18  19     public class CompressWhitespaceFilter : Stream 20     { 21         StringBuilder responseHtml; 22         const string _cssPattern = "(?
]*href\\s*=\\s*[\\\"\\']?(?
[^\"'>\\s]*)[\\\"\\']?[^>]*>)"; 23 const string _jsPattern = "(?
]*src\\s*=\\s*[\\\"\\']?(?
[^\"'>\\s]*)[\\\"\\']?[^>]*>)"; 24 25 private HttpApplication app; 26 public HttpApplication App 27 { 28 get { return app; } 29 set { app = value; } 30 } 31 32 private GZipStream _contentGZip; 33 private DeflateStream _content_Deflate; 34 private Stream _content; 35 private CompressOptions _options; 36 private bool disposed = false; 37 38 private CompressWhitespaceFilter() { } 39 public CompressWhitespaceFilter(Stream content, CompressOptions options) 40 { 41 42 responseHtml = new StringBuilder(); 43 if (options == CompressOptions.GZip) 44 { 45 this._contentGZip = new GZipStream(content, CompressionMode.Compress, true); 46 this._content = this._contentGZip; 47 } 48 else if (options == CompressOptions.Deflate) 49 { 50 this._content_Deflate = new DeflateStream(content, CompressionMode.Compress, true); 51 this._content = this._content_Deflate; 52 } 53 else 54 { 55 this._content = content; 56 } 57 this._options = options; 58 } 59 60 public override bool CanRead 61 { 62 get { return this._content.CanRead; } 63 } 64 65 public override bool CanSeek 66 { 67 get { return this._content.CanSeek; } 68 } 69 70 public override bool CanWrite 71 { 72 get { return this._content.CanWrite; } 73 } 74 75 ///
76 /// When overriding in a derived class, all buffers of the stream are cleared and all buffer data is written to the underlying device 77 /// 78 public override void Flush() 79 { 80 this._content.Flush(); 81 //Test 82 //this._content.Dispose(); 83 //this._contentGZip.Dispose(); 84 } 85 86 87 ///
88 /// 重写Dispose方法,释放派生类自己的资源,并且调用基类的Dispose方法 89 /// 使Gzip把缓存中余下的内容全部写入MemoryStream中,因为只有在Gzip流释放之后才能去承载对象中读取数据或判断数据大小 90 /// 91 ///
92 protected override void Dispose(bool disposing) 93 { 94 if (!this.disposed) 95 { 96 try 97 { 98 if (disposing) 99 {100 // Release the managed resources you added in this derived class here.101 //xx.Dispose();102 }103 104 // Release the native unmanaged resources you added in this derived class here.105 // xx.Close()106 107 //if (_contentGZip != null)108 // _contentGZip.Close();109 110 //if (_content_Deflate != null)111 // _content_Deflate.Close();112 113 this._content.Close();114 this.disposed = true;115 }116 finally117 {118 // Call Dispose on your base class.119 base.Dispose(disposing);120 }121 }122 }123 124 public override long Length125 {126 get { return this._content.Length; }127 }128 129 public override long Position130 {131 get132 {133 return this._content.Position;134 }135 set136 {137 this._content.Position = value;138 }139 }140 141 public override int Read(byte[] buffer, int offset, int count)142 {143 return this._content.Read(buffer, offset, count);144 }145 146 public override long Seek(long offset, SeekOrigin origin)147 {148 return this._content.Seek(offset, origin);149 }150 151 public override void SetLength(long value)152 {153 this._content.SetLength(value);154 }155 156 public override void Write(byte[] buffer, int offset, int count)157 {158 byte[] data = new byte[count + 1];159 Buffer.BlockCopy(buffer, offset, data, 0, count);160 string s = System.Text.Encoding.UTF8.GetString(data);161 s = Regex.Replace(s, "^\\s*", string.Empty, RegexOptions.Compiled | RegexOptions.Multiline);162 s = Regex.Replace(s, "\\r\\n", string.Empty, RegexOptions.Compiled | RegexOptions.Multiline);163 s = Regex.Replace(s, "
", string.Empty, RegexOptions.Compiled | RegexOptions.Multiline);164 byte[] outdata = System.Text.Encoding.UTF8.GetBytes(s);165 this._content.Write(outdata, 0, outdata.GetLength(0));166 }167 168 169 ///
170 /// Replcase stylesheet links with ones pointing to HttpHandlers that compress and cache the css171 /// 172 ///
173 ///
174 public string ReplaceCss(string html)175 {176 // create a list of the stylesheets177 List
stylesheets = new List
();178 // create a dictionary used for combining css in the same directory179 Dictionary
> css = new Dictionary
>();180 181 // create a base uri which will be used to get the uris to the css182 Uri baseUri = new Uri(app.Request.Url.AbsoluteUri);183 184 // loop through each match185 foreach (Match match in Regex.Matches(html, _cssPattern, RegexOptions.IgnoreCase))186 {187 // this is the enire match and will be used to replace the link188 string linkHtml = match.Groups[0].Value;189 // this is the href of the link190 string href = match.Groups[2].Value;191 192 // get a uri from the base uri, this will resolve any relative and absolute links193 Uri uri = new Uri(baseUri, href);194 string file = "";195 // check to see if it is a link to a local file196 if (uri.Host == baseUri.Host)197 {198 // check to see if it is local to the application199 if (uri.AbsolutePath.ToLower().StartsWith(app.Context.Request.ApplicationPath.ToLower()))200 {201 // this combines css files in the same directory into one file (actual combining done in HttpHandler)202 int index = uri.AbsolutePath.LastIndexOf("/");203 string path = uri.AbsolutePath.Substring(0, index + 1);204 file = uri.AbsolutePath.Substring(index + 1);205 if (!css.ContainsKey(path))206 css.Add(path, new List
());207 css[path].Add(file + (href.Contains("?") ? href.Substring(href.IndexOf("?")) : ""));208 // replace the origianl links with blanks209 html = html.Replace(linkHtml, "");210 // continue to next link211 continue;212 }213 else214 file = uri.AbsolutePath + uri.Query;215 }216 else217 file = uri.AbsoluteUri;218 string newLinkHtml = linkHtml.Replace(href, "css.axd?files=" + file);219 220 // just replace the link with the new link221 html = html.Replace(linkHtml, newLinkHtml);222 }223 224 StringBuilder link = new StringBuilder();225 link.AppendLine("");226 foreach (string key in css.Keys)227 {228 link.AppendLine(string.Format("
", key, string.Join(",", css[key].ToArray())));229 230 }231 232 // find the head tag and insert css in the head tag233 int x = html.IndexOf("
-1)236 {237 num = html.Substring(x).IndexOf(">");238 html = html.Insert(x + num + 1, link.ToString());239 }240 return html;241 }242 243 ///
244 /// Replcase javascript links with ones pointing to HttpHandlers that compress and cache the javascript245 /// 246 ///
247 ///
248 public string ReplaceJS(string html)249 {250 // if the javascript is in the head section of the html, then try to combine the javascript into one251 int start, end;252 if (html.Contains("
"))253 {254 start = html.IndexOf("
");256 string head = html.Substring(start, end - start);257 258 head = ReplaceJSInHead(head);259 260 html = html.Substring(0, start) + head + html.Substring(end);261 }262 263 // javascript that is referenced in the body is usually used to write content to the page via javascript, 264 // we don't want to combine these and place them in the header since it would cause problems265 // or it is a WebResource.axd or ScriptResource.axd266 if (html.Contains("
"))267 {268 start = html.IndexOf("
");270 string head = html.Substring(start, end - start);271 272 head = ReplaceJSInBody(head);273 274 html = html.Substring(0, start) + head + html.Substring(end);275 }276 277 return html;278 }279 280 ///
281 /// Replaces the js in the head tag. (see ReplaceCss for comments)282 /// 283 ///
284 ///
285 public string ReplaceJSInHead(string html)286 {287 List
javascript = new List
();288 Dictionary
> js = new Dictionary
>();289 290 Uri baseUri = new Uri(app.Request.Url.AbsoluteUri);291 foreach (Match match in Regex.Matches(html, _jsPattern, RegexOptions.IgnoreCase))292 {293 string linkHtml = match.Groups[0].Value;294 string src = match.Groups[2].Value;295 296 Uri uri = new Uri(baseUri, src);297 if (!Path.GetExtension(uri.AbsolutePath).Equals("js") && uri.AbsolutePath.Contains("WebResource.axd"))298 continue;299 if (uri.Host == baseUri.Host)300 {301 if (uri.AbsolutePath.ToLower().StartsWith(app.Context.Request.ApplicationPath.ToLower()))302 {303 int index = uri.AbsolutePath.LastIndexOf("/");304 string path = uri.AbsolutePath.Substring(0, index + 1);305 string file = uri.AbsolutePath.Substring(index + 1);306 if (!js.ContainsKey(path))307 js.Add(path, new List
());308 js[path].Add(file + (src.Contains("?") ? src.Substring(src.IndexOf("?")) : ""));309 }310 else311 javascript.Add(uri.AbsolutePath + uri.Query);312 313 }314 else315 javascript.Add(uri.AbsoluteUri);316 html = html.Replace(linkHtml, "");317 }318 319 int x = html.IndexOf("
");321 string link = "";322 323 foreach (string key in js.Keys)324 {325 link = string.Format("
", key, string.Join(",", js[key].ToArray()));326 html = html.Insert(x + num + 1, link + Environment.NewLine);327 328 }329 if (javascript.Count > 0)330 {331 link = string.Format("
", string.Join(",", javascript.ToArray()));332 html = html.Insert(x + num + 1, link + Environment.NewLine);333 }334 return html;335 }336 337 ///
338 /// Replaces the js in the body. (see ReplaceCss for comments)339 /// 340 ///
341 ///
342 public string ReplaceJSInBody(string html)343 {344 Uri baseUri = new Uri(app.Request.Url.AbsoluteUri);345 foreach (Match match in Regex.Matches(html, _jsPattern, RegexOptions.IgnoreCase))346 {347 string linkHtml = match.Groups[0].Value;348 string src = match.Groups[2].Value;349 350 351 Uri uri = new Uri(baseUri, src);352 if (!uri.AbsolutePath.EndsWith(".js") && !uri.AbsolutePath.Contains("WebResource.axd"))353 continue;354 string file = "";355 string path = "";356 if (uri.Host == baseUri.Host)357 {358 if (uri.AbsolutePath.ToLower().StartsWith(app.Context.Request.ApplicationPath.ToLower()))359 {360 int index = uri.AbsolutePath.LastIndexOf("/");361 path = uri.AbsolutePath.Substring(0, index + 1);362 file = uri.AbsolutePath.Substring(index + 1) + (src.Contains("?") ? src.Substring(src.IndexOf("?")) : "");363 }364 else365 file = uri.AbsolutePath + uri.Query;366 }367 else368 file = uri.AbsoluteUri;369 string newLinkHtml = linkHtml.Replace(src, path + "js.axd?files=" + file);370 html = html.Replace(linkHtml, newLinkHtml);371 }372 return html;373 }374 375 }376 }

在这里需要注意的是对GZIP 的释放,否则流数据会读取不到:

1         ///  2         /// 重写Dispose方法,释放派生类自己的资源,并且调用基类的Dispose方法 3         /// 使Gzip把缓存中余下的内容全部写入MemoryStream中,因为只有在Gzip流释放之后才能去承载对象中读取数据或判断数据大小 4         ///  5         ///  6         protected override void Dispose(bool disposing) 7         { 8             if (!this.disposed) 9             {10                 try11                 {12                     if (disposing)13                     {14                         // Release the managed resources you added in this derived class here.15                         //xx.Dispose();16                     }17 18                     //  Release the native unmanaged resources you added in this derived class here.19                     //  xx.Close()20 21                     //if (_contentGZip != null)22                     //    _contentGZip.Close();23 24                     //if (_content_Deflate != null)25                     //    _content_Deflate.Close();26 27                     this._content.Close();28                     this.disposed = true;29                 }30                 finally31                 {32                     // Call Dispose on your base class.33                     base.Dispose(disposing);34                 }35             }36         }

 

对于C#非托管资源释放(Finalize/Dispose)方法理解:

http://www.cnblogs.com/lzhdim/archive/2009/11/04/1595845.html

 

转载于:https://www.cnblogs.com/mschen/p/5904153.html

你可能感兴趣的文章
Reconstruct Itinerary
查看>>
Error与Exception的区别
查看>>
寒假瞎搞系列(6)
查看>>
Django1.10文档学习笔记五
查看>>
UVAlive4080_Warfare And Logistics
查看>>
前端自动化
查看>>
javascript中常见的几种循环遍历
查看>>
Linux多线程编程阅读链接
查看>>
WMAppManifest.xml
查看>>
scrapy框架 + selenium 爬取豆瓣电影top250......
查看>>
Snmp oid对应信息
查看>>
word-wrap和word-break的区别
查看>>
CSS实例:图片导航块
查看>>
Python实现翻译功能
查看>>
107. Binary Tree Level Order Traversal II
查看>>
Python中的TCP三次握手和四次挥手过程
查看>>
MVC 使用FileResult导出Excel数据文件
查看>>
出现“error c4430缺少类型说明符-假定为int。注意C++不支持默认int
查看>>
三种表示方式
查看>>
20160124.CCPP详解体系(0003天)
查看>>